/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright(c) 2020 - 2023 Allwinner Technology Co.,Ltd. All rights reserved. */
/*
 *  All Winner Tech, All Right Reserved. 2006-2016 Copyright (c)
 *
 *  File name   :        di_v23.c
 *
 *  Description :
 *
 *  History     :2016/01/18        zhengwj        initial version for DI_V2.0
 *               2016/10/09        zhengwj        modify for DI_V2.3
 *               2016/12/27        yulangheng     code of DI_V2.2 added
 *
 *  This file is licensed under the terms of the GNU General Public
 *  License version 2.  This program is licensed "as is" without any
 *  warranty of any kind, whether express or implied.
 */

#include "../di.h"
#include "../sunxi-di.h"
#include "di_type_v2x.h"
#include <linux/slab.h>
#include <asm/io.h>

volatile struct __di_dev_t *di_dev;
#if defined SUPPORT_DNS
volatile struct __dns_dev_t *dns_dev;
#endif

static struct __di_mode_t g_di_mode;

#define SETMASK(width, shift) ((width ? ((-1U) >> (32-width)) : 0)  << (shift))
#define CLRMASK(width, shift)   (~(SETMASK(width, shift)))
#define SET_BITS(shift, width, reg, val) \
		(((reg) & CLRMASK(width, shift)) | (val << (shift)))
/*
 * function: di_set_reg_base(void *base)
 * description: set di module register base
 * parameters: base <di module AHB memory mapping >
 * return   :
 */
s32 di_set_reg_base(void *base)
{
	di_dev = (struct __di_dev_t *)base;

#if defined SUPPORT_DNS
	dns_dev = (struct __dns_dev_t *)(base + 0x10000);
#endif

	return 0;
}

/*
 * function: di_get_reg_base(void)
 * description: get di module register base
 * parameters:
 * return   : di module AHB memory mapping
 */
void *di_get_reg_base(void)
{
	void *ret = NULL;

	ret = (void *)(di_dev);

	return ret;
}

/*
 * function: di_set_init(void)
 * description: set di module default register to ready de-interlace
 * parameters:
 * return   :
 */
#if defined DI_V23
#define IOMMU_ENABLE 1 /* DI_V2.3 : Enable IOMMU function */
#endif

s32 di_set_init(void)
{
#if defined DI_V23
	/* di_dev->output_path.bits.output_path = 0; */
	di_dev->outpath.dwval = 0x00000000;

	/* default setting of di */

	/* di_dev->ctrl.bits.dma_rand_access_en = 1 (iommu_enable) */
	di_dev->ctrl.dwval = 0x00000000 | (IOMMU_ENABLE << 16);

	/* int di_mode = 1;
	 * int motion_detc_en = 1;
	 * int diag_intp_en = 1;
	 * int flag_update_mode = 0;
	 * di_dev->mode.bits.di_mode_luma = di_mode;
	 * di_dev->mode.bits.di_mode_chroma = di_mode;
	 * di_dev->mode.bits.motion_detc_en = motion_detc_en;
	 * di_dev->mode.bits.diag_intp_en = diag_intp_en;
	 * di_dev->mode.bits.flag_update_mode = flag_update_mode;
	 * di_dev->mode.bits.in_field_mode =
	 *         (di_mode == DI_MODE_MOTION)? 0: 1;
	 */
	di_dev->mode.dwval = 0x00010031;

	/* di_dev->mdpara0.bits.minlumath = 0x4;
	 * di_dev->mdpara0.bits.maxlumath = 0xc;
	 * di_dev->mdpara0.bits.avglumashifter = 0x6;
	 * di_dev->mdpara0.bits.th_shift = 0x1;
	 */
	di_dev->mdpara0.dwval = 0x01060c04;

	/* di_dev->mdpara1.bits.mov_fac_nonedge = 0x2;
	 */
	di_dev->mdpara1.dwval = 0x20000000;

	/* di_dev->mdpara2.bits.chroma_spatical_th = 0x80;
	 * di_dev->mdpara2.bits.chroma_diff_th = 0x5;
	 * di_dev->mdpara2.bits.pix_static_th = 0x3;
	 */
	di_dev->mdpara2.dwval = 0x30058000;

	/* di_dev->dipara.bits.angle_limit = 0x14;
	 * di_dev->dipara.bits.angle_const_th = 0x5;
	 * di_dev->dipara.bits.luma_cur_fac_mod = 0x1;
	 * di_dev->dipara.bits.chroma_cur_fac_mod = 0x1;
	 */
	di_dev->dipara0.dwval = 0x00110514;

	/* di_dev->mdchpara.bits.blend_mode = 0x1;
	 * di_dev->mdchpara.bits.font_pro_en = 0x1;
	 * di_dev->mdchpara.bits.font_pro_th = 0x30;
	 * di_dev->mdchpara.bits.font_pro_fac = 0x4;
	 */
	di_dev->mdchpara.dwval = 0x04300101;

	/* di_dev->dipara1.bits.a = 0x4;
	 * di_dev->dipara1.bits.en = 0x1;
	 * di_dev->dipara1.bits.c = 0xa;
	 * di_dev->dipara1.bits.cmax = 0x40;
	 * di_dev->dipara1.bits.maxrat = 0x2
	 */
	di_dev->dipara1.dwval = 0x000240ac;
#elif defined DI_V22
	/* di_dev->output_path.bits.output_path = 0; */
	di_dev->outpath.dwval = 0x00000000;

	/* default setting of di */
	/* di_dev->ctrl.bits.dma_rand_access_en = 1 (iommu_enable) */
	di_dev->ctrl.dwval = 0x00000000;

	/* int di_mode = 1;
	 * int motion_detc_en = 1;
	 * int diag_intp_en = 1;
	 * int flag_update_mode = 0;
	 * di_dev->mode.bits.di_mode_luma = di_mode;
	 * di_dev->mode.bits.di_mode_chroma = di_mode;
	 * di_dev->mode.bits.motion_detc_en = motion_detc_en;
	 * di_dev->mode.bits.diag_intp_en = diag_intp_en;
	 * di_dev->mode.bits.flag_update_mode = flag_update_mode;
	 * di_dev->mode.bits.in_field_mode =
	 *         (di_mode == DI_MODE_MOTION)? 0: 1;
	 */
	di_dev->mode.dwval = 0x00010031;

	/* di_dev->mdpara0.bits.minlumath = 0x4;
	 * di_dev->mdpara0.bits.max_luma_th= 0x18;
	 * di_dev->mdpara0.bits.avglumashifter = 0x6;
	 * di_dev->mdpara0.bits.th_shift = 0x0;
	 */
	/* di_dev->mdpara0.dwval = 0x01060c04; */
	di_dev->mdpara0.dwval = 0x00061804;

	/* di_dev->f_prot_th = 0x80
	 * di_dev->f_prot_factor = 0x4
	 * di_dev->edge_th = 0x20
	 * di_dev->mov_fac_edge = 0x03
	 * di_dev->mov_fac_nonedge = 0x01
	 */
	di_dev->mdpara1.dwval = 0x13200480;

	/* di_dev->luma_spatial_th = 0x5
	 * di_dev->chroma_spatical_th = 0x80
	 * di_dev->chroma_diff_th = 0x5
	 * di_dev->erosion_bob_th = 0x7
	 * di_dev->pix_static_th = 0x3
	 */
	di_dev->mdpara2.dwval = 0x37058005;

	/* di_dev->dipara.bits.angle_limit = 0x14;
	 * di_dev->dipara.bits.angle_const_th = 0x5;
	 * di_dev->dipara.bits.luma_cur_fac_mod = 0x1;
	 * di_dev->dipara.bits.chroma_cur_fac_mod = 0x1;
	 */
	di_dev->dipara0.dwval = 0x00110514;

	/* di_dev->mdchpara.bits.blend_mode = 0x0;
	 * di_dev->mdchpara.bits.font_pro_en = 0x0;
	 * di_dev->mdchpara.bits.font_pro_th = 0x30;
	 * di_dev->mdchpara.bits.font_pro_fac = 0x4;
	 */
	di_dev->mdchpara.dwval = 0x04300000;
#endif

#if defined SUPPORT_DNS
	dns_dev->dns_ctl.dwval = 0x00000001; /* Enable Denoising */
	dns_dev->dns_lft_para0.dwval = 0x00ff9601;
	dns_dev->dns_lft_para1.dwval = 0xb24e3c80;
	dns_dev->dns_lft_para2.dwval = 0x77153a00;
	dns_dev->dns_lft_para3.dwval = 0x000000ff;
	dns_dev->iqa_blkdt_para0.dwval = 0x0000c810;

#endif

	g_di_mode.di_mode = DI_MODE_MOTION;
	g_di_mode.update_mode = DI_UPDMODE_FIELD;

	return 0;
}

#define di_writel(val, addr) writel(val, (void __iomem *)(addr))
#define di_readl(addr) readl((void __iomem *)(addr))

void DI_SET_BITS(unsigned int *reg_addr, unsigned int bits_val,
			unsigned int shift, unsigned int width)
{
	unsigned int reg_val;

	reg_val = di_readl(reg_addr);
	reg_val = SET_BITS(shift, width, reg_val, bits_val);
	di_writel(reg_val, reg_addr);
}

/*
 * function: di_reset(void)
 * description: stop di module
 * parameters:
 * return   :
 */
s32 di_reset(void)
{
	unsigned int reset = 0x1;

	di_dev->ctrl.bits.reset = reset;
	/* DI_SET_BITS(&di_dev->ctrl.dwval, reset, 0, 1); */
	while (reset < 20)
		reset++;
	reset = 0;
	di_dev->ctrl.bits.reset = reset;
	/* DI_SET_BITS(&di_dev->ctrl.dwval, reset, 0, 1); */
	return 0;
}

/*
 * function: di_start(void)
 * description: start a de-interlace function
 * parameters:
 * return   :
 */
s32 di_start(void)
{
	di_dev->ctrl.bits.start = 0x1;

	return 0;
}

/*
 * function: di_irq_enable(unsigned int enable)
 * description: enable/disable di irq
 * parameters: enable <0-disable; 1-enable>
 * return   :
 */
s32 di_irq_enable(unsigned int enable)
{
	di_dev->intr.bits.int_en = (enable & 0x1);

	return 0;
}

/*
 * function: di_get_status(void)
 * description: get status of di module
 * parameters:
 * return  :  <0-Writeback finish; 1-Writeback no start; 2-Writeback-ing;
 *            (-1)-Undefined
 */
s32 di_get_status(void)
{
	int ret;
	unsigned int busy;
	unsigned int finish;

	finish = di_dev->status.bits.finish_sts;
	busy = di_dev->status.bits.busy;

	if (busy)
		ret = 2;
	else if (finish == 0 && busy == 0)
		ret = 1;
	else if (finish)
		ret = 0;
	else
		ret = -1;

	return ret;
}

/*
 * function: di_irq_clear()
 * description: clear irq status
 * parameters:
 * return   :
 */
s32 di_irq_clear(void)
{
	di_dev->status.bits.finish_sts = 0x1;

	return 0;
}

void DI_SET_FORMAT(unsigned char fmt)
{
	di_dev->fmt.bits.fmt = fmt;
}

void DI_SET_SIZE(unsigned int width, unsigned int height)
{
	di_dev->size.dwval = ((height - 1) & 0x7ff) << 16 |
			     ((width - 1) & 0x7ff);
#if defined SUPPORT_DNS
	dns_dev->dns_size.dwval = ((height - 1) & 0x7ff) << 16 |
			     ((width - 1) & 0x7ff);
#endif

}

void DI_CALC_INADDR(struct __di_buf_addr_t *pre_addr,
		    struct __di_buf_addr_t *cur_addr,
		    struct __di_buf_addr_t *nxt_addr,
		    struct __di_buf_size_t *size, unsigned int field,
		    unsigned char fmt, unsigned int top_field_first,
		    unsigned long long addr[4][3], unsigned int fieldpitch[3])
{
	unsigned int pitch[3];

	pitch[0] = size->fb_width;

	if (fmt == DI_FMT_PLANAR420 || fmt == DI_FMT_PLANAR422) {
		pitch[1] = ((size->fb_width + 1) >> 1);
		pitch[2] = pitch[1];
	} else {
		pitch[1] = (((size->fb_width + 1) >> 1) << 1);
		pitch[2] = 0;
	}

	fieldpitch[0] = pitch[0] << 1;
	fieldpitch[1] = pitch[1] << 1;
	fieldpitch[2] = pitch[2] << 1;

	if (top_field_first == 1) {
		if (field == 0) {
			addr[0][0] = pre_addr->ch0_addr;
			addr[0][1] = pre_addr->ch1_addr;
			addr[0][2] = pre_addr->ch2_addr;
			addr[1][0] = pre_addr->ch0_addr + pitch[0];
			addr[1][1] = pre_addr->ch1_addr + pitch[1];
			addr[1][2] = pre_addr->ch2_addr + pitch[2];
			addr[2][0] = cur_addr->ch0_addr;
			addr[2][1] = cur_addr->ch1_addr;
			addr[2][2] = cur_addr->ch2_addr;
			addr[3][0] = cur_addr->ch0_addr + pitch[0];
			addr[3][1] = cur_addr->ch1_addr + pitch[1];
			addr[3][2] = cur_addr->ch2_addr + pitch[2];
		} else {
			addr[0][0] = pre_addr->ch0_addr + pitch[0];
			addr[0][1] = pre_addr->ch1_addr + pitch[1];
			addr[0][2] = pre_addr->ch2_addr + pitch[2];
			addr[1][0] = cur_addr->ch0_addr;
			addr[1][1] = cur_addr->ch1_addr;
			addr[1][2] = cur_addr->ch2_addr;
			addr[2][0] = cur_addr->ch0_addr + pitch[0];
			addr[2][1] = cur_addr->ch1_addr + pitch[1];
			addr[2][2] = cur_addr->ch2_addr + pitch[2];
			addr[3][0] = nxt_addr->ch0_addr;
			addr[3][1] = nxt_addr->ch1_addr;
			addr[3][2] = nxt_addr->ch2_addr;
		}
	} else {
		if (field == 0) {
			addr[0][0] = pre_addr->ch0_addr;
			addr[0][1] = pre_addr->ch1_addr;
			addr[0][2] = pre_addr->ch2_addr;
			addr[1][0] = cur_addr->ch0_addr + pitch[0];
			addr[1][1] = cur_addr->ch1_addr + pitch[1];
			addr[1][2] = cur_addr->ch2_addr + pitch[2];
			addr[2][0] = cur_addr->ch0_addr;
			addr[2][1] = cur_addr->ch1_addr;
			addr[2][2] = cur_addr->ch2_addr;
			addr[3][0] = nxt_addr->ch0_addr + pitch[0];
			addr[3][1] = nxt_addr->ch1_addr + pitch[1];
			addr[3][2] = nxt_addr->ch2_addr + pitch[2];
		} else {
			addr[0][0] = pre_addr->ch0_addr + pitch[0];
			addr[0][1] = pre_addr->ch1_addr + pitch[1];
			addr[0][2] = pre_addr->ch2_addr + pitch[2];
			addr[1][0] = pre_addr->ch0_addr;
			addr[1][1] = pre_addr->ch1_addr;
			addr[1][2] = pre_addr->ch2_addr;
			addr[2][0] = cur_addr->ch0_addr + pitch[0];
			addr[2][1] = cur_addr->ch1_addr + pitch[1];
			addr[2][2] = cur_addr->ch2_addr + pitch[2];
			addr[3][0] = cur_addr->ch0_addr;
			addr[3][1] = cur_addr->ch1_addr;
			addr[3][2] = cur_addr->ch2_addr;
		}
	}
}

void DI_SET_INPUT(unsigned int pitch[3], unsigned long long addr[4][3])
{
	di_dev->inpicth0.dwval = pitch[0] & 0xffff;
	di_dev->inpicth1.dwval = pitch[1] & 0xffff;
	di_dev->inpicth2.dwval = pitch[2] & 0xffff;

	di_dev->in0add0.dwval = (unsigned int)(addr[0][0] & 0xffffffffLL);
	di_dev->in0add1.dwval = (unsigned int)(addr[0][1] & 0xffffffffLL);
	di_dev->in0add2.dwval = (unsigned int)(addr[0][2] & 0xffffffffLL);
	di_dev->in0addhb.dwval =
		((unsigned int)((addr[0][0] & 0xff00000000LL)>>32) |
		 (unsigned int)((addr[0][1] & 0xff00000000LL)>>24) |
		 (unsigned int)((addr[0][2] & 0xff00000000LL)>>16));

	di_dev->in1add0.dwval = (unsigned int)(addr[1][0] & 0xffffffffLL);
	di_dev->in1add1.dwval = (unsigned int)(addr[1][1] & 0xffffffffLL);
	di_dev->in1add2.dwval = (unsigned int)(addr[1][2] & 0xffffffffLL);
	di_dev->in1addhb.dwval =
		((unsigned int)((addr[1][0] & 0xff00000000LL)>>32) |
		 (unsigned int)((addr[1][1] & 0xff00000000LL)>>24) |
		 (unsigned int)((addr[1][2] & 0xff00000000LL)>>16));

	di_dev->in2add0.dwval = (unsigned int)(addr[2][0] & 0xffffffffLL);
	di_dev->in2add1.dwval = (unsigned int)(addr[2][1] & 0xffffffffLL);
	di_dev->in2add2.dwval = (unsigned int)(addr[2][2] & 0xffffffffLL);
	di_dev->in2addhb.dwval =
		((unsigned int)((addr[2][0] & 0xff00000000LL)>>32) |
		 (unsigned int)((addr[2][1] & 0xff00000000LL)>>24) |
		 (unsigned int)((addr[2][2] & 0xff00000000LL)>>16));

	di_dev->in3add0.dwval = (unsigned int)(addr[3][0] & 0xffffffffLL);
	di_dev->in3add1.dwval = (unsigned int)(addr[3][1] & 0xffffffffLL);
	di_dev->in3add2.dwval = (unsigned int)(addr[3][2] & 0xffffffffLL);
	di_dev->in3addhb.dwval =
		((unsigned int)((addr[3][0] & 0xff00000000LL)>>32) |
		 (unsigned int)((addr[3][1] & 0xff00000000LL)>>24) |
		 (unsigned int)((addr[3][2] & 0xff00000000LL)>>16));

}

void DI_SET_OUTPUT(struct __di_buf_size_t *size, unsigned char fmt,
			unsigned long long addr[3])
{
	unsigned int pitch[3];

	pitch[0] = size->fb_width;

	if (fmt == DI_FMT_PLANAR420 || fmt == DI_FMT_PLANAR422) {
		pitch[1] = ((size->fb_width + 1) >> 1);
		pitch[2] = pitch[1];
	} else {
		pitch[1] = (((size->fb_width + 1) >> 1) << 1);
		pitch[2] = 0;
	}

	di_dev->outpicth0.dwval = pitch[0] & 0xffff;
	di_dev->outpicth1.dwval = pitch[1] & 0xffff;
	di_dev->outpicth2.dwval = pitch[2] & 0xffff;

	di_dev->outadd0.dwval = (unsigned int)(addr[0] & 0xffffffffLL);
	di_dev->outadd1.dwval = (unsigned int)(addr[1] & 0xffffffffLL);
	di_dev->outadd2.dwval = (unsigned int)(addr[2] & 0xffffffffLL);
	di_dev->outaddhb.dwval =
		((unsigned int)((addr[0] & 0xff00000000LL)>>32) |
		 (unsigned int)((addr[1] & 0xff00000000LL)>>24) |
		 (unsigned int)((addr[2] & 0xff00000000LL)>>16));

}

void DI_SET_FLAG(unsigned long long in_flag_add,
		 unsigned long long out_flag_add, unsigned int pitch)
{
	di_dev->flagpitch.dwval = pitch & 0xffff;

	di_dev->inflagadd.dwval = (unsigned int)(in_flag_add & 0xffffffffLL);
	di_dev->outflagadd.dwval = (unsigned int)(out_flag_add & 0xffffffffLL);
	di_dev->flagaddhb.dwval =
		((unsigned int)((in_flag_add & 0xff00000000LL)>>32) |
		 (unsigned int)((out_flag_add & 0xff00000000LL)>>24));

}

void DI_SET_CURFAC(unsigned int curfac)
{
	di_dev->dipara0.bits.luma_cur_fac_mod = curfac;
	di_dev->dipara0.bits.chroma_cur_fac_mod = curfac;
}

void DI_SET_POLAR(unsigned int polar)
{
	di_dev->polar.dwval = polar & 0x1;
}

void DI_SET_FLAG_AUTO_UPD_MODE(unsigned int mode)
{
#if defined DI_V23
	di_dev->mode.bits.flag_auto_update_mode = mode;
#endif
}

int DI_SW_PARA_TO_REG(unsigned char format)
{
	/* deinterlace input pixel format */
	if (format <= DI_FORMAT_NV21)
		return DI_FMT_UVCOMB420;
	else if (format == DI_FORMAT_YV12)
		return DI_FMT_PLANAR420;
	else if (format == DI_FORMAT_YUV422_SP_UVUV ||
		   format == DI_FORMAT_YUV422_SP_VUVU)
		return DI_FMT_UVCOMB422;
	else if (format == DI_FORMAT_YUV422P)
		return DI_FMT_PLANAR422;
	/* DE_INF("not supported de-interlace input pixel format :%d
	 *		in di_sw_para_to_reg\n",format);
	 */
	return -1;
}

/*
 * function: di_set_para(__di_para_t *para)
 * description: set parameters to ready a de-interlace function
 * parameters: para <parameters which set from ioctrl>
 *             in_flag_add/out_flag_add <flag address malloc in driver>
 *             polar <0 - select even line for source line;
 *                    1 - select odd line for source line>
 *             di_mode <di mode set by app>
 * return  :   <0 - set OK; -1 - para NULL>
 */
s32 di_set_para(struct __di_para_t2 *para, void *in_flag_add,
		void *out_flag_add, u32 field)
{
	int fmt;
	unsigned int width, height;
	unsigned long long inaddr[4][3], outaddr[3];
	unsigned int inpitch[3];
	/* FIXME: flagpitch can be changed according to source */
	unsigned int flagpitch = 0x200;
	unsigned int curfac = 0;
	unsigned int faum;

	struct __di_buf_addr_t pre_addr;
	struct __di_buf_addr_t cur_addr;
	struct __di_buf_addr_t nxt_addr;
	/* struct __di_buf_addr_t out_addr; */
	/* struct __di_buf_addr_t flg_addr; */
	struct __di_buf_size_t in_size;
	struct __di_buf_size_t out_size;

	if (para == NULL) {
		/* DE_WRN("input parameter can't be null!\n"); */
		return -1;
	}

	/* FORMAT and SIZE */
	fmt = DI_SW_PARA_TO_REG(para->input_fb.format);

	if (fmt < 0) {
		/* DE_WRN("para->input_fb.format=%d isnot supported!\n",
		 * para->input_fb.format);
		 */
		return -1;
	}

	width = para->source_regn.width;
	height = para->source_regn.height;
	DI_SET_FORMAT(fmt);
	DI_SET_SIZE(width, height);

	/* INPUT FRAMEBUFFER ADDRESS and PITCH */
	pre_addr.ch0_addr = para->pre_fb.addr[0];
	pre_addr.ch1_addr = para->pre_fb.addr[1];
	pre_addr.ch2_addr = para->pre_fb.addr[2];

	cur_addr.ch0_addr = para->input_fb.addr[0];
	cur_addr.ch1_addr = para->input_fb.addr[1];
	cur_addr.ch2_addr = para->input_fb.addr[2];

	nxt_addr.ch0_addr = para->next_fb.addr[0];
	nxt_addr.ch1_addr = para->next_fb.addr[1];
	nxt_addr.ch2_addr = para->next_fb.addr[2];

	/* in_size.width = para->source_regn.width; */
	/* in_size.height = para->source_regn.height; */
	in_size.fb_width = para->input_fb.size.width;
	in_size.fb_height = para->input_fb.size.height;

	DI_CALC_INADDR(&pre_addr, &cur_addr, &nxt_addr, &in_size, field, fmt,
			para->top_field_first, inaddr, inpitch);
	DI_SET_INPUT(inpitch, inaddr);

	/* OUTPUT FRAMEBUFFER ADDRESS and PITCH */
	outaddr[0] = para->output_fb.addr[0];
	outaddr[1] = para->output_fb.addr[1];
	outaddr[2] = para->output_fb.addr[2];

	/* out_size.width = para->out_regn.width; */
	/* out_size.height = para->out_regn.height; */
	out_size.fb_width = para->output_fb.size.width;
	out_size.fb_height = para->output_fb.size.height;

	DI_SET_OUTPUT(&out_size, fmt, outaddr);

	/* MOTION INFORMATION ADDRESS and PITCH */
	DI_SET_FLAG((unsigned long)in_flag_add,
			(unsigned long)out_flag_add, flagpitch);

	/* DI PARAMERTES */
#if defined DI_V23
	/* DI_V2.3 */
	curfac = (para->top_field_first == 0) ? 5 : 4;
#elif defined DI_V22
	curfac = (g_di_mode.di_mode != DI_MODE_WEAVE) ? 1 :
		 (para->top_field_first == 0) ? 5 : 4;
#endif

	DI_SET_CURFAC(curfac);
	DI_SET_POLAR(field);

	faum = (para->top_field_first == 0) ? 1 : 0;
	DI_SET_FLAG_AUTO_UPD_MODE(faum);

	return 0;
}

/*
 * function: di_set_mode(struct __di_mode_t *di_mode)
 * description: set DI mode
 * parameters: di_mode <update_mode and di_mode set by app>
 * return  :
 */
void di_set_mode(struct __di_mode_t *di_mode)
{
	unsigned char flag_update_mode;
	unsigned char motion_detc_en;
	unsigned char diag_intp_en;
	unsigned char mode;
	unsigned char in_field_mode;

	g_di_mode.di_mode = di_mode->di_mode;
	g_di_mode.update_mode = di_mode->update_mode;

	flag_update_mode = di_mode->update_mode & 0x1;
	motion_detc_en = (di_mode->di_mode < DI_MODE_MOTION) ? 0 : 1;
	diag_intp_en = (di_mode->di_mode < DI_MODE_INTP) ? 0 : 1;
	mode = (di_mode->di_mode < DI_MODE_INTP) ? 0 : 1;
	in_field_mode = (di_mode->di_mode == DI_MODE_MOTION) ? 0 : 1;

	di_dev->mode.dwval = mode |
			    (motion_detc_en << 4) |
			    (diag_intp_en << 5) |
			    (flag_update_mode << 8) |
			    (mode << 16) |
			    (in_field_mode << 31);

}

s32 di_internal_clk_enable(void)
{
	return 0;
}

s32 di_internal_clk_disable(void)
{
	return 0;
}
